package config

import (
	"encoding/json"
	jwt "github.com/dgrijalva/jwt-go"
	"io/ioutil"
	"math/rand"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"
	"unicode"
)

type System struct {
	Id         int    `json:"id"`
	Nickname   string `orm:"column(nickname)" json:"nickname"`
	Tel        string `orm:"column(tel)" json:"tel"`
	Headimg    string `orm:"column(headimg)" json:"headimg"`
	CreateTime int    `orm:"column(create_time)" json:"create_time"`
}

var singKey = "your_secret_key" //用户生成token的密钥

// CreateToken  生成用户token
func CreateToken(id int, nickname string, mobile string, avatar string) (string, error) {

	timeEd := time.Now().Unix()
	var system System
	system.Id = id
	system.Nickname = nickname
	system.Tel = mobile
	system.Headimg = avatar
	system.CreateTime = int(timeEd)

	signingKey := []byte(singKey)

	str, err := json.Marshal(system)
	if err != nil {
		return "", err
	}
	expireTime := GetExpireTime()

	claims := &jwt.StandardClaims{
		// 过期时间
		ExpiresAt: time.Now().Add(expireTime).Unix(),
		// 发行者
		Issuer: string(str),
	}

	// 创建JWT令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 签名令牌
	signedToken, err := token.SignedString(signingKey)

	return signedToken, err
}

// TokenDecrypt 解析Token
func TokenDecrypt(token string) (System, error) {
	var system System
	// 使用你在设置JWT中间件时定义的签名密钥来解密和解码token
	tokens, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
		// 这里的[]byte("your_signing_key")应该是你的签名密钥
		return []byte(singKey), nil
	})

	if err != nil {
		return system, err
	}
	claims, _ := tokens.Claims.(jwt.MapClaims)

	var iss = claims["iss"]
	iss1 := iss.(string)

	err1 := json.Unmarshal([]byte(iss1), &system)
	if err1 != nil {
		return system, err1
	}

	return system, nil
}

// Random 生成随机数
func Random(num int) string {
	// 初始化随机数种子
	rand.Seed(time.Now().UnixNano())

	// 创建一个字符集，包含数字和小写字母
	charSet := []rune("abcdefghijklmnopqrstuvwxyz0123456789")

	// 创建一个4位数的切片，用于存放随机生成的数字和字母
	str := make([]rune, num)

	// 生成不重复的随机数字和字母
	for i := range str {
		// 从字符集中随机选择一个字符
		str[i] = charSet[rand.Intn(len(charSet))]
		// 移除已使用的字符，防止下次选到重复的
		charSet = append(charSet[:i], charSet[i+1:]...)
	}

	return string(str)

}

// GetExpireTime 获取token过期时间
func GetExpireTime() time.Duration {
	m := Expire_Time * 60 //获取过期分钟数
	expireTime := time.Duration(m) * time.Minute

	return expireTime
}

// GetChildren getChildren 将从数据库查询到的Menu切片组装成树形结构
func GetChildren(content []map[string]interface{}) []map[string]interface{} {

	formatMenu := make(map[int]map[string]interface{})

	for _, item := range content {
		id, _ := strconv.Atoi(strconv.FormatFloat(item["id"].(float64), 'f', 0, 64))
		formatMenu[id] = item

	}
	// 得益于都是地址操作,可以直接往父级塞
	for _, v := range formatMenu {
		parentId, _ := strconv.Atoi(strconv.FormatFloat(v["parent_id"].(float64), 'f', 0, 64))
		if formatMenu[parentId] == nil {
			continue
		}
		if formatMenu[parentId]["children"] == nil {
			formatMenu[parentId]["children"] = []map[string]interface{}{}
		}
		formatMenu[parentId]["children"] = append(formatMenu[parentId]["children"].([]map[string]interface{}), v)
	}
	var treeMenu []map[string]interface{}
	for _, innerMap := range formatMenu {
		treeMenu = append(treeMenu, innerMap)
	}

	return treeMenu

}

// Contains 检查字符串是否在字符串切片中
func Contains(s []string, e string) bool {
	for _, a := range s {
		if a == e {
			return true
		}
	}
	return false
}

// GetColumnValue 取出某一列的值
func GetColumnValue(s interface{}, columnName string) interface{} {
	sValue := reflect.ValueOf(s).Elem()
	fieldValue := sValue.FieldByName(columnName)
	if !fieldValue.IsValid() {
		panic("No such column: " + columnName)
	}
	return fieldValue.Interface()
}

// StructsToMap 将结构体数据装换[]map
func StructsToMap(items interface{}) []map[string]interface{} {
	slice := reflect.ValueOf(items)
	result := make([]map[string]interface{}, slice.Len())

	for i := 0; i < slice.Len(); i++ {
		result[i] = make(map[string]interface{})
		structFieldValues(slice.Index(i).Interface(), result[i])
	}

	return result
}

func structFieldValues(item interface{}, data map[string]interface{}) {
	structValue := reflect.ValueOf(item)
	if structValue.Kind() == reflect.Ptr {
		structValue = structValue.Elem()
	}

	structType := structValue.Type()

	for i := 0; i < structValue.NumField(); i++ {
		fieldName := structType.Field(i).Name
		data[fieldName] = structValue.Field(i).Interface()
	}
}

// ToMap 数据interface{} 转换为map[string]interface{} 方便取值
func ToMap(i interface{}) (map[string]interface{}, bool) {

	val := reflect.ValueOf(i)
	if val.Kind() == reflect.Map {
		m := make(map[string]interface{})

		for _, key := range val.MapKeys() {
			m[key.Interface().(string)] = val.MapIndex(key).Interface()
		}
		return m, true
	}
	return nil, false
}

// RemoveFirstUnderscore  去掉蛇形第一个下划线前面的字符
func RemoveFirstUnderscore(s string) string {
	// 正则表达式匹配以下划线开头，后面跟随任何字符的模式
	// 并将这部分替换为仅保留下划线
	re := regexp.MustCompile(`^[^_]*_`)
	return re.ReplaceAllString(s, "_")
}

// Case2Camel 蛇形转大驼峰
func Case2Camel(name string) string {
	name = strings.Replace(name, "_", " ", -1)
	name = strings.Title(name)
	return strings.Replace(name, " ", "", -1)
}

// Ucfirst ⾸字母⼤写
func Ucfirst(str string) string {
	for i, v := range str {
		return string(unicode.ToUpper(v)) + str[i+1:]
	}
	return ""
}

// ToLowerFirst 首字母转小写
func ToLowerFirst(s string) string {
	if s == "" {
		return s
	}
	r := []rune(s)
	r[0] = unicode.ToLower(r[0])
	return string(r)
}

// GetUppercaseLetters 首字母转小写
func GetUppercaseLetters(str string) []string {
	regex := regexp.MustCompile(`[A-Z]`)
	return regex.FindAllString(str, -1)
}

// UnsetFileContent 删除文件内的内容
func UnsetFileContent(path string, num int) {
	data, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	lines := len(data)
	if lines <= num {
		return
	}

	data = data[:lines-num]

	err = ioutil.WriteFile(path, data, 0777)
	if err != nil {
		panic(err)
	}
}
